CSVCHK
======

Проверка потока данных формата CSV на соответствие указанной структуре данных.

Исполняемые модули: <https://gitverse.ru/panarinv/index/content/master/programs/csvchk>.  
Исходный код: <https://gitverse.ru/panarinv/csvchk>.


ВОЗМОЖНОСТИ
-----------

Программа проверяет входящий поток данных формата CSV на соответствие структуре.
Строки данных, прошедшие проверку, передаются в стандартный выходной поток.
Сводный отчёт о найденных ошибках выводится в стандартный поток ошибок.

Особенности работы:

* Корректные строки передаются в выходной поток без изменений;
* Ошибочные строки не передаются в выходной поток и не накапливаются в памяти;
* Системные и непечатные символы заменяются на условные обозначения (см. далее).

Программа НЕ предназначена:

* для изменения формата или корректировки данных;
* для сложных проверок (уникальность значений, математических выражений и т.п.);
* для получения дословного перечня ошибочных строк
  (выводится только сводный отчёт с примерами ошибок).


ТРЕБОВАНИЯ
----------

Установка не требуется, достаточно скопировать исполняемый файл для нужной ОС.
От пользователей требуется знания и навыки работы с форматом CSV,
 понимание концепции стандартных потоков ввода/вывода данных.


ИСПОЛЬЗОВАНИЕ
-------------

Программа использует текстовый (консольный) интерфейс.
Исходные (проверяемые) данные получает из стандартного входного потока,
 прошедшие проверку строки выводит в выходной, отчёт - в поток ошибок.

Формат команды:

    csvchk [параметры] <ввод >вывод 2>ошибки
    
    Параметры:
      -d <символ>    - разделитель полей в потоке данных (по умолчанию TAB);
      -s <структура> - структура потока данных;
      -header        - первая строка не проверяется (для пропуска заголовков);
      -trim          - триммировать (удалять пробелы до и после) значения.

Структура - строка с перечнем типов данных полей в потоке (разделитель - ";").  
Пример структуры - "`i2*;b;i4;f;n(3,2);d;c(10)`".  
Типы данных:

- b (bool)      - логическое значение (true/false 1/0);
- i (int)       - знаковое целое число 2, 4 или 8 байт;
- r (real)      - число с плавающей точкой, 4 байта;
- f (float)     - число с плавающей точкой, 8 байт;
- n (numeric)   - число с произвольной точностью;
- d (date)      - дата (yyyy-mm-dd);
- t (timestamp) - дата время (yyyy-mm-dd hh:mm:ss);
- c (char)      - текст фиксированной длинны;
- v (varchar)   - текст переменной длинны.

Размеры целочисленных типов задаются в байтах после имени: i2, i4, i8.
Максимальный размер текста указывается в скобках: c(10), v(250).
Для типа numeric указывается точность и масштаб: n(18,4).
Символом "*" помечаются обязательные для заполнения поля.
Если указан неизвестный тип данных,
 то проверка значения на соответствие типу данных не выполняется.

Сводный отчёт об ошибках - таблица со следующими полями (разделитель - TAB):

- fld_index: номер поля в исходных данных (начиная с 0);
- fld_type:  тип данных поля;
- err_type:  тип ошибки (см. далее);
- err_value: пример ошибочного значения;
- err_line:  пример строки, содержащей ошибку;
- err_count: количество ошибок данного типа в данном поле.

Типы ошибок:

- FRMT: нарушен формат строки данных (неправильное количество полей);
- NULL: отсутствует значение в обязательном для заполнения поле;
- TYPE: значение не соответствует типу данных поля;
- SIZE: превышение максимальной длинны текста;
- OVRF: переполнение числового значения.


ПРИМЕР
------

Структура для примера - "i2*;b;i4;I8;t;f8;n(7,4);c(10)", разделитель - ",".

Исходный (входной) поток данных:

    1,false,123,456,2018-07-24,12345.6789,123.4567,Строка 1
    2,,,,,,,
    3,,,,,
    ,,,,,,,
    5,,,,,,,,,
    6,1,123,456,2018-07-24 12:34:56,"12345.6789E+8",   .4567   ,Стр. 2;   
    255,false,-123,-456,1000-01-01,-.12345678,-.87654321,"Строка
    АБВ"
    -1,ДА,a123,_,01.02.2018,1..2,1234.56,"Длин¦ная
    строка"

Получаемый (выходной) поток данных:

    1,false,123,456,2018-07-24,12345.6789,123.4567,Строка 1
    2,,,,,,,
    6,1,123,456,2018-07-24 12:34:56,12345.6789E+8,.4567,Стр. 2;
    255,false,-123,-456,1000-01-01,-.12345678,-.87654321,"Строка
    АБВ"

Отчёт об ошибках:

    fld_index  fld_type  err_type  err_value              err_line                                                    err_count
           -1            FRMT                             record on line 3: wrong number of fields                            2
            0  i2        NULL                             ¦¦¦¦¦¦¦                                                             1
            1  b         TYPE      ДА                     -1¦ДА¦a123¦_¦01.02.2018¦1..2¦1234.56¦Длин\u00A6ная\nстрока          1
            2  i4        TYPE      a123                   -1¦ДА¦a123¦_¦01.02.2018¦1..2¦1234.56¦Длин\u00A6ная\nстрока          1
            3  i8        TYPE      _                      -1¦ДА¦a123¦_¦01.02.2018¦1..2¦1234.56¦Длин\u00A6ная\nстрока          1
            4  t         TYPE      01.02.2018             -1¦ДА¦a123¦_¦01.02.2018¦1..2¦1234.56¦Длин\u00A6ная\nстрока          1
            5  f8        TYPE      1..2                   -1¦ДА¦a123¦_¦01.02.2018¦1..2¦1234.56¦Длин\u00A6ная\nстрока          1
            6  n(7,4)    OVRF      1234.56                -1¦ДА¦a123¦_¦01.02.2018¦1..2¦1234.56¦Длин\u00A6ная\nстрока          1
            7  c(10)     SIZE      Длин\u00A6ная\nстрока  -1¦ДА¦a123¦_¦01.02.2018¦1..2¦1234.56¦Длин\u00A6ная\nстрока          1

Пояснения к примеру:

Строки 1, 2, 6 и 255 полностью соответствует структуре и проходят проверку.
Во второй строке первое поле обязательно, остальные могут быть пустыми.
Перевод строки в 255 не мешает прохождению проверки,
 т.к. всё значение экранировано кавычками.

Пояснения к отчёту об ошибках (по сочетаниям индекса поля и типа ошибки):

* -1|FRMT - Две строки (3-я и 5-я) с неправильным количеством полей
            (индекс и тип поля не выводится - ошибочна вся строка,
             вместо примера строки выводится сообщение СУБД);
* 0|NULL - пустое значение в первом (обязательном) поле (индекс поля - 0);
* 1|TYPE - тип данных - "`ДА`" не считается булевым значением (b);
* 2|TYPE - тип данных - "`a123`" не является целым числом типа i4;
* 3|TYPE - тип данных - "`_`" не является целым числом типа i8;
* 4|TYPE - тип данных - "`01.02.2018`" корректная дата, но в неправильном формате;
* 5|TYPE - тип данных - "`1..2`" не является натуральным числом типа f8;
* 6|OVRF - переполнение числового типа - тип "n(7,4)"
           допускает только 3 цифры целой части и хранит только 4 цифры дробной;
* 7|SIZE - строка длиннее 10 символов
           (символ "`¦`" в ИСХОДНЫХ данных заменяется на код "`\u00A6`").


ОПИСАНИЕ
--------

### Поддерживаемые типы данных

Программа поддерживает следующие обозначения (псевдонимы) типов данных:

- b, bool, boolean;
- i2, int2, i16, int16, smallint;
- i4, int4, i32, int32, i, int, integer;
- i8, int8, i64, int64, bigint;
- r, real, f4, float4, f32, float32;
- f, float, f8, float8, f64, float64, double;
- n, numeric, decimal (с указанием точности и масштаба);
- d, date, t, timestamp, timestamptz;
- c, char, character, v, varchar (с указанием максимальной длинны).

### Примеры значений и строк с ошибками

В отчёт выводятся примеры ошибочных значений и строк данных.
Описание формируется только для первой ошибки данного типа в данном поле.
Последующие ошибки данного "типа-поля" увеличивают счётчик ошибок.
Одна и та же строка данных может отображаться в отчёте более одного раза
 (для каждого уникального сочетания типа ошибки и поля данных).

Для наглядного отображения специальные и непечатные символы преобразуются:

- пробел заменяется на символ точки "`·`" (`\u00B7`);
- символы табуляции, возврата каретки и переноса строки на "`\t`", "`\r`" и "`\n`";
- символ экранирования (обратный слэш, "`\`") повторяется дважды ("`\\`");
- символы за пределами печатных (отображаемых) знаков
  заменяются кодом формата "`\u####`", где "`####`" код символа.

В примере строки данных разделители полей отображаются символом "`¦`" (`\u00A6`).

### Получение структуры данных

При загрузке данных в базу может быть полезно получить структуру потока данных
 из метаданных целевой таблицы в базе.

Пример SQL-запроса для получения структуры потока данных (СУБД PostgreSQL):

    SELECT string_agg(f, ';')
    FROM (
    SELECT
        CASE data_type
            WHEN 'character varying' THEN 'varchar'
            WHEN 'double precision' THEN 'float8'
            WHEN 'timestamp without time zone' THEN 'timestamp'
            WHEN 'timestamp with time zone' THEN 'timestamptz'
            ELSE data_type
        END
        || CASE WHEN data_type in ('numeric','decimal')
           and numeric_precision is not null and numeric_scale is not null THEN
           '('||Cast((numeric_precision - numeric_scale) as text)||')'
           ELSE ''
           END
        || Coalesce(
           '('||Cast(character_maximum_length as text)||')',
           '')
        || CASE WHEN is_nullable='NO' THEN '*' ELSE '' END
        as f
    FROM information_schema.columns
    WHERE table_schema='<схема-таблицы>'
          and table_name='<имя-таблицы>'
          and column_name in ('<имена-полей,...>')
    ORDER BY Position(','||column_name||',' in ',<имена-полей,...>,')
    ) a

Параметры:

- "`<схема-таблицы>`" и "`<имя-таблицы>`" - задают таблицу для извлечения структуры;
- "`<имена-полей,...>`" - задают перечень полей и их порядок (разделитель ",").



ЛИЦЕНЗИЯ
--------

Это свободное программное обеспечение.
Вы можете повторно распространять или изменять его
 в соответствии с условиями лицензии BSD.
Полный текст лицензии в файле LICENSE.

`(c) 2019-2024 Вячеслав Панарин (panarinv@mail.ru)`
